from PySide2.QtCore import Signal, QObject

from D5Core.Details.D5Api import D5Api,APIRequestType
from D5Core.D5Models.Details.D5ModelBase import D5Model
from D5Core.D5Common import *
from D5Core.Details.D5ModelCreator import D5ModelCreator
import json
from D5Core.D5Common import D5Singleton


class ModelListSig(QObject):
    """
    模型列表信号类，用于在模型列表更新时发出信号。
    
    该类继承自QObject，并定义了一个信号selected_model_sig，
    用于通知模型列表的选中模型发生变化。
    """
    selected_model_sig: Signal = Signal(str)


@D5Singleton
class ModelList:

    """
    模型列表管理类，用于获取和维护系统中的模型列表。
    
    该类使用单例模式（通过D5Singleton装饰器实现），确保在整个应用程序中
    只有一个ModelList实例，用于集中管理所有可用的模型。
    
    :ivar __model_list_map: 存储模型ID到模型对象的映射字典
    :vartype __model_list_map: dict[str, D5Model]
    """
    def __init__(self):
        """
        初始化ModelList实例。
        
        创建一个空的模型列表映射字典。
        """
        self.__model_list_map:dict[str,D5Model] = {}
        self.selected_model :D5Model= None
        self.__model_list_sig = ModelListSig()
        self.__model_list_sig.selected_model_sig.connect(self.__handle_selected_model)
    
    def emit_selected_model(self, jsonstr:str):
        self.__model_list_sig.selected_model_sig.emit(jsonstr)

    def __handle_selected_model(self, jsonstr:str):
        res = json.loads(jsonstr)
        model_id = res.get("uuid", "")
        if model_id:
            self.selected_model = self.get_model(model_id)
        else:
            self.selected_model = None



    def get_model_list_map(self):
        """
        从API获取模型列表并更新本地模型映射。
        
        该方法通过D5Api发送同步请求获取所有可用模型的信息，
        然后使用D5ModelCreator将返回的数据转换为D5Model对象，
        并存储在内部的模型映射字典中。
        
        :return: 包含所有模型的映射字典，键为模型ID，值为D5Model对象
        :rtype: dict[str, D5Model]
        :raises KeyError: 当API响应缺少必要字段时
        :raises Exception: 当处理模型数据时发生错误
        """
        req_id = D5Api().generate_uuid()
        payload = {
            "uuid": req_id,
            "type": APIRequestType.READ_MODEL_LIST.value,
            "content": "{}"
        }
        
        json_str = D5Api().request_sync(req_id,json.dumps(payload))

        try:
            response = json.loads(json_str)
            if "content" not in response:
                raise KeyError("响应缺少 content 字段")
                
            content = json.loads(response["content"])
            models = content.get("Models", [])
            
            for model_data in models:
                self.__model_list_map[model_data.get("id", "")] = D5ModelCreator.create_model(model_data)
        except Exception as e:
            print(f"模型处理错误: {str(e)}")
        return self.__model_list_map
    
    def get_model(self, model_id:str)->D5Model:
        """
        根据模型ID获取对应的D5Model对象。
        
        :param model_id: 模型的唯一标识符
        :type model_id: str"
        :return: 对应的D5Model对象，如果不存在则返回None"
        :rtype: D5Model or None
        """
        list_map =  self.get_model_list_map()
        return list_map.get(model_id, None)
    
    def delete_model(self, ActorId:str) -> bool:
        uuid = D5Api().generate_uuid()
        payload = {
            "uuid": uuid,
            "type": APIRequestType.DELETE_MODEL.value,
            "content": json.dumps({"ActorId": ActorId})
        }
        json_str = D5Api().request_sync(uuid, json.dumps(payload), 100)
        res = json.loads(json_str)
        success = res.get("success", False)
        if success:
            self.__model_list_map.pop(ActorId, None)
        return success
    
    def create_model(self, resource_id:str) ->D5Model:
        uuid = D5Api().generate_uuid()
        payload = {
            "uuid": uuid,
            "type": APIRequestType.CREATE_IMPORT_MODEL.value,
            "content": json.dumps({
                "resource_id": resource_id,
            })
        }
        json_str = D5Api().request_sync(uuid, json.dumps(payload), 100)
        res = json.loads(json_str)
        success = res.get("success", False)
        model_id = ""
        if success:
            res = res.get("response", "")
            res = json.loads(res)
            model_id = res.get("actor_id", "")
        list_map = self.get_model_list_map()
        return list_map.get(model_id, None)
    
    def import_resource_data(self, resource_path:str,timeout:int = 100) :
        return D5Api().import_model_sync(resource_path, timeout)
    

    
    
    

